package com.lsh.oms.provider.service.endpoint;

import com.alibaba.dubbo.config.annotation.Service;
import com.lsh.base.common.model.CommonResult;
import com.lsh.oms.core.records.core.Return;
import com.lsh.oms.core.records.core.ReturnRepository;
import com.lsh.oms.core.records.core.ReturnResult;
import com.lsh.oms.core.service.tool.Criteria;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.Map;

@Path("returns")
@Service(protocol = "rest", timeout = 30000)
@Slf4j
public class ReturnsResource implements com.lsh.oms.api.endpoint.core.ReturnsResource {

    @Resource
    private ReturnRepository returns;

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response query(@Context UriInfo uriInfo,
                          @DefaultValue("1") @QueryParam("page") long page,
                          @DefaultValue("20") @QueryParam("page-limit") long limit) {
        return Response
                .ok(returns.query(Criteria.of(uriInfo), page, limit))
                .build();
    }

    @GET
    @Path("summary")
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response summary(@Context UriInfo uriInfo) {
        return Response.ok(returns.summary(Criteria.of(uriInfo))).build();
    }

    @GET
    @Path("{id}")
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response find(@PathParam("id") Long id,
                         @QueryParam("details-required") @DefaultValue(value = "true") boolean detailsRequired) {
        return Response
                .ok(findReturn(id))
                .build();
    }

    @POST
    @Path("{id}/run")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response launch(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).run(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response check(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).check(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/confirm")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response confirm(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).confirm(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/pre-deliver")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response preDeliver(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).preDeliver(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/deliver")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response deliver(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).deliver(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/return")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response returned(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).returned(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/cancel")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response cancel(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).cancel(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/refund")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response refund(@PathParam("id") Long id, Map<String, Object> request) {
        findReturn(id).refund(request);
        return Response.ok(CommonResult.success()).build();
    }

    @GET
    @Path("{id}/return-results")
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response returnResults(@PathParam("id") Long id,
                                  @Context UriInfo uriInfo,
                                  @DefaultValue("1") @QueryParam("page") long page,
                                  @DefaultValue("20") @QueryParam("page-limit") long limit) {
        return Response.ok(findReturn(id).returnResults(Criteria.of(uriInfo), page, limit)).build();
    }

    @GET
    @Path("{id}/return-results/{result-id}")
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response returnResult(@PathParam("id") Long id,
                                 @PathParam("result-id") Long resultId) {
        return Response.ok(findReturnResult(id, resultId)).build();
    }

    @GET
    @Path("{id}/relations")
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response relations(@PathParam("id") Long id) {
        return Response
                .ok(findReturn(id).relations())
                .build();
    }

    @POST
    @Path("{id}/return-results/{result-id}/payment-notify")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response returnResultPaymentNotify(@PathParam("id") Long id,
                                              @PathParam("result-id") Long resultId,
                                              Map<String, Object> request) {
        findReturnResult(id, resultId).paymentNotify(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/return-results/{result-id}/run")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response executeReturnResult(@PathParam("id") Long id,
                                        @PathParam("result-id") Long resultId,
                                        Map<String, Object> request) {
        findReturnResult(id, resultId).run(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/return-results/{result-id}/issue")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response issueReturnResult(@PathParam("id") Long id,
                                      @PathParam("result-id") Long resultId,
                                      Map<String, Object> request) {
        findReturnResult(id, resultId).issue(request);
        return Response.ok(CommonResult.success()).build();
    }

    @POST
    @Path("{id}/details/{detail-id}")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    @Override
    public Response updateDetail(@PathParam("id") Long id,
                                 @PathParam("detail-id") Long detailId,
                                 Map<String, Object> request) {
        findReturnDetail(id, detailId).update(request);
        return Response.ok(CommonResult.success()).build();
    }

    private Return findReturn(Long id) {
        return returns.find(id, true).orElseThrow(NotFoundException::new);
    }

    private ReturnResult findReturnResult(Long id, Long resultId) {
        return findReturn(id).returnResult(resultId).orElseThrow(NotFoundException::new);
    }

    private Return.ReturnDetail findReturnDetail(Long id, Long detailId) {
        return findReturn(id).returnDetail(detailId).orElseThrow(NotFoundException::new);
    }
}
